package com.javabi.unix.line;

import static java.lang.Character.isWhitespace;

/**
 * A Line Tokenizer, with utility methods to provide simple data types for the tokens.
 */
public class LineTokenizer implements ILineTokenizer {

	private final String line;
	private int index = 0;

	public LineTokenizer(String line) {
		if (line == null) {
			throw new NullPointerException("line");
		}
		this.line = line;
	}

	@Override
	public boolean hasNext() {
		return index < line.length();
	}

	@Override
	public String next() {
		if (index >= line.length()) {
			throw new IllegalArgumentException("end of line");
		}

		// Skip whitespace
		skipWhitespace();

		// Parse token
		int startIndex = index;
		while (index < line.length()) {
			char character = line.charAt(index);
			if (isWhitespace(character)) {
				break;
			}
			index++;
		}

		int endIndex = index;
		return line.substring(startIndex, endIndex);
	}

	public String next(String delimiter) {
		if (delimiter.isEmpty()) {
			throw new IllegalArgumentException("delimiter is empty");
		}
		if (index >= line.length()) {
			throw new IllegalArgumentException("end of line");
		}

		// Skip whitespace
		skipWhitespace();

		// Parse token
		int startIndex = index;
		int endIndex = line.indexOf(delimiter, startIndex);
		if (endIndex == -1) {
			throw new IllegalStateException("delimiter '" + delimiter + "' not found in '" + line + "', index=" + index);
		}
		index = endIndex + delimiter.length();
		return line.substring(startIndex, endIndex);
	}

	@Override
	public void remove() {
		throw new UnsupportedOperationException();
	}

	@Override
	public void skipWhitespace() {
		while (index < line.length()) {
			char character = line.charAt(index);
			if (!isWhitespace(character)) {
				break;
			}
			index++;
		}
	}

	@Override
	public String remaining() {
		if (index >= line.length()) {
			throw new IllegalArgumentException("end of line");
		}

		skipWhitespace();

		int startIndex = index;
		index = line.length();
		return line.substring(startIndex);
	}

	@Override
	public int nextInt() {
		return Integer.parseInt(next());
	}

	@Override
	public long nextLong() {
		return Long.parseLong(next());
	}

	@Override
	public float nextFloat() {
		return Float.parseFloat(next());
	}

	@Override
	public double nextDouble() {
		return Double.parseDouble(next());
	}

	@Override
	public void skip(String expected) {
		if (expected == null) {
			throw new NullPointerException("expected");
		}

		String token = next();
		if (!expected.equals(token)) {
			throw new IllegalArgumentException("expected: '" + expected + "', actual: '" + token + "'");
		}
	}

}
